using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
namespace OrderSystem
{
  
    public class Client
    {//init client
        public Client()
        {
            Name = "";
            Phone = "";
        }
        //带参数
        public Client(string name, string phone)
        {
            Name = name;
            Phone = phone;
        }

        private string name;
      
        public string Name
        { 
            get => name;
            set => name = value.Trim(); 
        }

        private string phone;
   
        public string Phone
        {
            get => phone;
            set => phone = IsPhoneValid(value)
                ? value.Trim()
                : throw new InvalidPhoneException(value);
        }

        public override string ToString()
        {
            return $"姓名: {Name}, 电话: {Phone}";
        }

        public override bool Equals(object obj)
        {
            if (obj == null || GetType() != obj.GetType())
            {
                return false;
            }
            Client other = (Client)obj;
            return Name == other.Name && Phone == other.Phone;
        }

        public override int GetHashCode() => Name.GetHashCode() ^ Phone.GetHashCode();

        private static bool IsPhoneValid(string phone)
        {
            foreach (char ch in phone)
            {
                if (!char.IsDigit(ch) && !char.IsWhiteSpace(ch) && ch != '-')
                {
                    return false;
                }
            }
            return true;
        }
    }

    class InvalidPhoneException : ApplicationException
    {
        public InvalidPhoneException(string phone)
            : base($"\"{phone}\" 输入错误.") { }
    }
}

namespace OrderSystem
{
    [Serializable]
    public class Commodity
    {
        public Commodity()
        {
            Name = "";
            Price = 0;
        }

        public Commodity(string name, double price)
        {
            Name = name;
            Price = price;
        }


        public string Name { get; set; }

        private double price;
 
        public double Price
        {
            get => price;
            set => price = (value >= 0)
                ? value
                : throw new InvalidPriceException(value);
        }

        public override string ToString() => $"商品名: {Name}, 价格: {Price}";

        public override bool Equals(object obj)
        {
            if (obj == null || GetType() != obj.GetType())
            {
                return false;
            }
            Commodity other = (Commodity)obj;
            return Name == other.Name && Price == other.Price;
        }

        public override int GetHashCode() => Name.GetHashCode() ^ Price.GetHashCode();
    }


    public class InvalidPriceException : ApplicationException
    {
        public InvalidPriceException(double price)
            : base($"{price} 输入非法.") { }
    }
}
namespace OrderSystem
{

    public class OrderDetail
    {
        public OrderDetail()
        {
            Commodity = new Commodity();
            Count = 1;
        }

        public OrderDetail(string address, Commodity commodity, int count)
        {
            if (address == null || commodity == null)
            {
                throw new NullArgumentException();
            }
            if (count <= 0)
            {
                throw new InvalidCountException(count);
            }
           
            Commodity = commodity;
            Count = count;
        }

  

        public Commodity Commodity { get; set; }


        public int Count
        {
            get => count;
            set => count = (value > 0)
                            ? value
                            : throw new InvalidCountException(value);
        }

        public override string ToString()
        {
            return $"商品: {Commodity}\n" +
                   $"件数: {Count}";
        }

        public override bool Equals(object obj)
        {
            if (obj == null || GetType() != obj.GetType())
            {
                return false;
            }
            OrderDetail other = (OrderDetail)obj;
            return Commodity == other.Commodity
                   && Count == other.Count;
        }

        public override int GetHashCode() =>  Commodity.GetHashCode()^ Count;

        private int count;
    }


    public class InvalidCountException : ApplicationException
    {
        public InvalidCountException(int count)
            : base($"Count {count} 输入错误.") { }
    }
}
namespace OrderSystem
{

    public class Order
    {
        public Order()
        {
            Client = new Client();
            Details = new List<OrderDetail>();
        }

        public Order(Client client, List<OrderDetail> details)
        {
            Client = client;
            Details = details;
        }

        private int id = -1;

        public int Id
        {
            get => id >= 0 ? id : throw new ApplicationException();
            set => id = value;
        }

        public Client Client { get; set; }


        public List<OrderDetail> Details { get; set; }


        public double PriceSum
        {
            get
            {
                double sum = 0;
                Details.ForEach(detail => sum += detail.Commodity.Price * detail.Count);
                return sum;
            }
        }

        public bool ContainsCommodity(Commodity commodity) =>
            Details.Find(detail => detail.Commodity.Equals(commodity)) != null;

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append($"id: {Id}\n\n")
              .Append($"客户:\n{Client}\n\n")
              .Append($"总和: {PriceSum}\n\n")
              .Append("细节:\n");
            Details.ForEach(detail => sb.Append($"{detail}\n"));
            sb.Append("\n");
            return sb.ToString();
        }


        public override bool Equals(object obj)
        {
            if (obj == null || GetType() != obj.GetType())
            {
                return false;
            }
            Order other = (Order)obj;
            return Client.Equals(other.Client)
                && Details.Equals(other.Details);
        }

        public override int GetHashCode() => Client.GetHashCode()
                                           ^ Details.GetHashCode();
    }

    public class NullArgumentException : ApplicationException
    {
        public NullArgumentException(string argName)
            : base($"Argument \"{argName}\" is null.") { }
        public NullArgumentException() { }
    }
}
namespace OrderSystem
{

    public class OrderService : IEnumerable<Order>
    {

        public List<Order> Orders { get; private set; } = new List<Order>();


        public int AddOrder(Order order)
        {
            if (order == null)
            {
                throw new NullArgumentException();
            }
            if (Exists(order))
            {
                throw new OrderExistException();
            }
            order.Id = idCounter;
            idCounter++;
            Orders.Add(order);
            return order.Id;
        }

        public bool Exists(Order order) => Orders.Contains(order);


        public bool Exists(int id) => Orders.Find(order => order.Id == id) != null;


        public void RemoveOrder(int id)
        {
            int rmCnt = Orders.RemoveAll(order => order.Id == id);
            if (rmCnt == 0)
            {
                throw new OrderNotExistException();
            }
        }

        public void RemoveOrder(Order order)
        {
            if (!Exists(order))
            {
                throw new OrderNotExistException();
            }
            Orders.Remove(order);
        }

        public Order Get(int id)
        {
            return Orders.Find(order => order.Id == id);
        }

        public IEnumerator<Order> GetEnumerator()
        {
            foreach (Order order in Orders)
            {
                yield return order;
            }
        }

        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

        public void ForEach(Action<Order> action)
        {
            foreach (Order order in Orders)
            {
                action?.Invoke(order);
            }
        }

        public void Export(string path)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(List<Order>));
            using (FileStream fs = new FileStream(path, FileMode.Create))
            {
                serializer.Serialize(fs, Orders);
            }
        }


        private int idCounter = 0;


        public static OrderService Import(string path)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(List<Order>));
            using (FileStream fs = new FileStream(path, FileMode.Open))
            {
                OrderService service = new OrderService
                {
                    Orders = (List<Order>)serializer.Deserialize(fs)
                };
                int maxId = -1;
                service.Orders.ForEach(order => maxId = Math.Max(maxId, order.Id));
                service.idCounter = maxId + 1;
                return service;
            }
        }
    }

    public class OrderExistException : ApplicationException
    { }

    public class OrderNotExistException : ApplicationException
    { }
}